#pragma once
#include<iostream>
#include<unordered_map>
#include"ResourceManage.h"
#include"AsyncIncreWriteThread.h"
using namespace std;

class Transaction{ //一个事务不会有多个线程操作，操作不上锁。

    unordered_map<ResourceInfo, ResourceManage*, ResInfoHash> acquireResources;

    unordered_set<ResourceManage*> usedResources;   //保证没有相同(地址)的资源

    tuple<vector<pair<ResourceInfo, vector<Record*>>>, vector<pair<ResourceInfo, vector<IndexRecord*>>>, vector<pair<ResourceInfo, vector<uint64_t>>>> getComitInfo(){
        vector<pair<ResourceInfo, vector<Record*>>> upDateInfo;
        vector<pair<ResourceInfo, vector<IndexRecord*>>> indexUpDateInfo;
        vector<pair<ResourceInfo, vector<uint64_t>>> bitMapUpDateInfo;
        for(ResourceManage* res : usedResources){
            const ResourceInfo& resInfo = res->getResourceInfo();
            const DISKTYPE& diskType = res->getDiskType();
            if(diskType == BLOCK || diskType == BLOCKDEL){
                const vector<Record*>& tmpRecords = res->getComitRecords(); //获取提交记录
                upDateInfo.push_back(make_pair(resInfo, tmpRecords));
            }
            else if(diskType == SLINDEX){
                const vector<IndexRecord*>& tmpIndexRecords = res->getComitIndexRecords();  //获取提交记录
                indexUpDateInfo.push_back(make_pair(resInfo, tmpIndexRecords));
            }
            else if(diskType == BITMAP){
                const vector<uint64_t>& tmpBitMapRecords = res->getComitBitMapRecords();  //获取提交记录
                bitMapUpDateInfo.push_back(make_pair(resInfo, tmpBitMapRecords));
            }
            else{
                throw string("diskType error");
            }
        }
        return make_tuple(upDateInfo, indexUpDateInfo, bitMapUpDateInfo);
    }

    vector<Record*> getAllRecords(const vector<pair<ResourceInfo, vector<Record*>>>& upDateInfo){
        vector<Record*> allRecords;
        for(const auto& it : upDateInfo){
            const vector<Record*>& tmpRecords = it.second;
            allRecords.insert(allRecords.end(), tmpRecords.begin(), tmpRecords.end());
        }
        return allRecords;
    }

    //写这么丑不调用Record的getByteData是为了少一次拷贝
    char* getAllRecordsBuffer(const vector<Record*>& allRecords){
        return Record::getRecordsBuffer(allRecords);
    }

    void releaseResAndClear(){
        for(ResourceManage* res : usedResources){
            res->releaseResLock();      //释放资源锁
        }
        for(const auto& it : acquireResources){
            it.second->releaseHoldLock();     //后释放持有锁 防止释放持有锁后立马被释放
        }
        usedResources.clear();
        acquireResources.clear();
    }

public:

    void comit(){
        const tuple<vector<pair<ResourceInfo, vector<Record*>>>, vector<pair<ResourceInfo, vector<IndexRecord*>>>, vector<pair<ResourceInfo, vector<uint64_t>>>>& comitInfo = getComitInfo();
        const vector<Record*>& allRecords = getAllRecords(get<0>(comitInfo));
        char* buffer = getAllRecordsBuffer(allRecords);
        IOUtil::appRecordFromEnd(buffer, allRecords.size() * Record::getRecordSize());
        AsyncIncreWriteThread::addComitInfoToWriteThread(get<0>(comitInfo), get<1>(comitInfo), get<2>(comitInfo));
        releaseResAndClear();  //释放资源并清空 方便事务池复用
        MemUtil::asyncClearPtrArrMem(buffer);
    }

    void rollback(){
        for(ResourceManage* res : usedResources){
            res->memRollBack();
        }
        releaseResAndClear();  //释放资源并清空 方便事务池复用
    }

    ResourceManage* getRes(const ResourceInfo& resInfo){
        const auto& it = acquireResources.find(resInfo);
        return it == acquireResources.end() ? nullptr : it->second;
    }

    void putRes(ResourceManage* res){
        acquireResources.insert(make_pair(res->getResourceInfo(), res));
    }

    void getResLock(ResourceManage* res, const LOCKTYPE& lockType){
        res->getResLock(lockType);              //没获取到会向外抛异常 在最外面回滚
        usedResources.insert(res);              //在指定时间获取到了锁，将其加入事务获取的资源集。
    }

};



class TransactionPool{

    static TransactionPool* transactionPool;

    vector<Transaction*> pool;

    QSemaphore* RemainSem;

    QMutex mutex;

    void init(const int& totalCount){
        for(int i = 0; i < totalCount; i++){
            pool.push_back(new Transaction());
        }
        RemainSem = new QSemaphore(totalCount);
    }

    Transaction* mutexGetTransaction(){
        mutex.lock();
        Transaction* transaction = pool.back();
        pool.pop_back();
        mutex.unlock();
        return transaction;
    }

    void mutexPutTransaction(Transaction* transaction){
        mutex.lock();
        pool.push_back(transaction);
        mutex.unlock();
    }

public:
    TransactionPool(const int& totalCount){
        init(totalCount);
    }

    ~TransactionPool(){
        MemUtil::clearVecMem(pool);
        MemUtil::clearPtrMem(RemainSem);
    }

    Transaction* getTransaction(){
        RemainSem->acquire();
        return mutexGetTransaction();
    }

    void putTransaction(Transaction* transaction){
        mutexPutTransaction(transaction);
        RemainSem->release();
    }

    static void initTransactionPool(const int& totalCount){
        transactionPool = new TransactionPool(totalCount);
    }

    static Transaction* poolGetTransaction(){
        return transactionPool->getTransaction();
    }

    static void poolPutTransaction(Transaction* transaction){
        transactionPool->putTransaction(transaction);
    }
};

